import java.util.LinkedList;


/*
 * A thread pool is a group of a limited number of threads that are used to execute tasks.
 */

public class ThreadPool extends ThreadGroup 
{
	
	private boolean isAlive;
	private LinkedList taskQueue;
	private int threadID;
	private static int threadPoolID;
	
	/**
	 *Creates new parameter @param numThreads the number of threads in the pool 
	 */
	
	public ThreadPool(int numThreads)
	{
		super("ThreadPool -" + (threadPoolID++));
		setDaemon(true);
		
		isAlive=true;
		
		taskQueue = new LinkedList();
		for (int i=0; i<= numThreads;i++)
		{
			new PooledThread().start();
		}
	}
	
	/**
	 * Request a new task to run. this method returns inmediately and the task executes on the next available idle thread in this pool.
	 * tasks start execution FIFO, @param task the task to run, if null no action
	 * @throws IllegalStateException uf this threadpool is already closed
	 */
	
	public synchronized void runTask(Runnable task)
	{
		if (!isAlive)
		{
			throw new IllegalStateException();
		}
		if (task!=null)
		{
			taskQueue.add(task);
			notify();
		}
	}
	
	protected synchronized Runnable getTask() throws InterruptedException
	{
		while (taskQueue.size() ==0)
		{
			if (!isAlive)
			{
				return (null);
			}
			wait();
		}
		return (Runnable)taskQueue.removeFirst();
	}
	/***
	 * Closes this threadpool and returns inmediately.all thread are stopped an any waiting task is not executed. once a pool is closed no more task can run on the pool
	 */
	
	public synchronized void close()
	{
		if (isAlive)
		{
			isAlive=false;
			taskQueue.clear();
			interrupt();
		}
	}

	/*
	 * Closes this pool and wairs for all running threads to finish. any waiting task are executed
	 */
	
	public void join()
	{
		//notify all waiting threads that this pool is no longer alive
		synchronized (this)
		{
			isAlive=false;
			notifyAll();
		}
		
		//wait 4 all thread to finish 
		Thread[] threads = new Thread[activeCount()];
		int count = enumerate(threads);
		for (int i=0; i<count; i++)
		{
			try{
				threads[i].join();
			}
			catch (InterruptedException ex)
			{
				
			}
		}
		
	}
	
	/*
	 * A ppoleadthread is a thread in a pool group, designed to run tasks (runnables)
	 */
	
	private class PooledThread extends Thread{
		
		public PooledThread()
		{
			super(ThreadPool.this, "PooledThread-" + (threadID++));
		}
		
		public void run()
		{
			while (!isInterrupted())
			{
				//get a task to tun
				Runnable task = null;
				try
				{
					task=getTask();
				}
				catch (InterruptedException ex){}
				
				//if gettask is null or interrupted close the thread
				
				if (task==null)
				{
					return;
				}
				
				//run the task, and eat any exception it throws
				
				try{
					task.run();
				}
				catch (Throwable t)
				{
					uncaughtException(this,t);
				}
			}
		}
		
	}
	
}
